﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;

namespace Umbrella.Whs
{
    public class RunProcessLogged
    {
        private readonly log4net.ILog _log;

        public string ExeFile
        {
            get; 
            private set;
        }

        public string Arguments
        {
            get;
            private set;
        }

        public string WorkingDirectory
        {
            get;
            private set;
        }

        public void Run()
        {
            _log.Info("Starting process: " + this.ExeFile /*+ " " + this.Arguments <--- some calls may contain passwords */);

            try
            {
                var pi = new ProcessStartInfo()
                {
                 FileName = this.ExeFile,
                 Arguments = this.Arguments,
                 WorkingDirectory = this.WorkingDirectory,
                 CreateNoWindow = true,
                 UseShellExecute = false,
                 RedirectStandardOutput = true,
                 RedirectStandardError = true
                };

                var p = new Process();

                p.StartInfo = pi;

                // register logging
                if (_log.IsDebugEnabled)
                {
                    p.OutputDataReceived += new DataReceivedEventHandler(p_OutputDataReceived);
                }

                if (_log.IsWarnEnabled)
                {
                    p.ErrorDataReceived += new DataReceivedEventHandler(p_ErrorDataReceived);
                }

                // start the process
                if (!p.Start())
                    throw new Exception("Failed to start process");

                // start logging
                if (_log.IsDebugEnabled)
                    p.BeginOutputReadLine();

                if (_log.IsWarnEnabled)
                    p.BeginErrorReadLine();

                // wait for result
                p.WaitForExit();

                _log.Info("Exit code: " + p.ExitCode);

                if (p.ExitCode != 0)
                    throw new ProcessFailedException(p.ExitCode);

            }
            catch (Exception x)
            {
                _log.Error("Failed to run process: " + this.ExeFile, x);

                throw;
            }
        }

        private void p_ErrorDataReceived(object sender, DataReceivedEventArgs e)
        {
            if (!string.IsNullOrEmpty(e.Data))
                _log.Warn(e.Data);
        }

        private void p_OutputDataReceived(object sender, DataReceivedEventArgs e)
        {
            if (!string.IsNullOrEmpty(e.Data))
                _log.Debug(e.Data);
        }

        public RunProcessLogged(string exeFile, string arguments, string workingDir)
        {
            if (string.IsNullOrEmpty(exeFile))
                throw new ArgumentException("null or empty", "exeFile");

            this.ExeFile = exeFile;
            this.Arguments = arguments;
            this.WorkingDirectory = workingDir;

            _log = log4net.LogManager.GetLogger(GetType().FullName + "#" + Path.GetFileNameWithoutExtension(exeFile));
        }
    }
}